home *** CD-ROM | disk | FTP | other *** search
/ The Very Best of Atari Inside / The Very Best of Atari Inside 1.iso / mint / mntlb20 / lib / crtinit.c < prev    next >
C/C++ Source or Header  |  1992-04-27  |  9KB  |  346 lines

  1. /*
  2.  *
  3.  * Crtinit: C run-time initialization code.
  4.  * Written by Eric R. Smith, and placed in the public domain.
  5.  * Use at your own risk.
  6.  *
  7.  * 01/03/89 ++jrb
  8.  *    The (new) meaning of _stksize: (thanks to allan pratt for the feedback)
  9.  *
  10.  *    _stksize            meaning
  11.  *      -1L        keep all of memory (except MINFREE at top) and do
  12.  *            mallocs from own heap, with heap grown upwards towards
  13.  *            stack, and the stack growing down towards heap,
  14.  *            with a minimum slush between them so that they
  15.  *            dont meet (only checked while malloc'ing). With
  16.  *            this model, further spawning is not possible, but it is
  17.  *            well suited for programs such as gcc-cc1 etc.
  18.  *            Thanks to Piet van Oostrum & Atze Dijkstra for this idea
  19.  *
  20.  *    0L        keep minimum amount of memory. this is also the
  21.  *            case when _stksize is undefined by the user.
  22.  *    1L        keep 1/4 of memory, free 3/4 ( as in Alcyon GEMSTART)
  23.  *    2L        keep 2/4 (1/2), free rest
  24.  *    3L        keep 3/4, free 1/4
  25.  *    other        keep that many bytes
  26.  *    -other        keep |other| bytes, use the heap for mallocs
  27.  *
  28.  * 02/14/90 ++jrb (thanks edgar)
  29.  *    auto acc detect
  30.  *    undump friendly
  31.  *
  32.  * NOTE: dumping applications should use _initial_stack instead: if
  33.  *     !=0, then _stksize is initialized from _initial_stack, and
  34.  *     mallocs are always from internal heap. (TeX works much better now),
  35.  *     thanks edgar!
  36.  *
  37.  * Acc convention:
  38.  *    user sets _heapbase to bottom of stack + heap area
  39.  *         sets _stksize to the size of this area
  40.  *         at startup, sp will be set to top of this area
  41.  *         (_heapbase  + _stksize ) and malloc()'s will happen from heap.
  42.  *        (note malloc() and *not* Malloc())
  43.  *
  44.  * 02/16/90 ++jrb
  45.  *  - bug fix: dont get screwed by desktop launch when fast bit is set
  46.  *             convert env string to format usable
  47.  *        (atari get your act together!!)
  48.  */
  49.  
  50. #include <basepage.h>
  51. #include <osbind.h>
  52. #include "lib.h"
  53.  
  54. #define isspace(c) ((c) == ' '||(c) == '\t')
  55. #define MINFREE    (8L * 1024L)        /* free at least this much mem */
  56.                     /* on top */
  57. #define MINKEEP (8L * 1024L)        /* keep at least this much mem */
  58.  
  59. BASEPAGE *_base;
  60. char **environ;
  61. static long argc;
  62. static char **argv;
  63.  
  64. /*
  65.  * initial stack is used primarily by dumping application,
  66.  * if it is, malloc is always from heap, and _stksize is init
  67.  * from initial_stack (to preserve the value in the undumped run)
  68.  */
  69. long _initial_stack;        /* .comm __initial_size, 4 */
  70. extern long _stksize;        /* picked up from user or from stksiz.c */
  71.  
  72. /* set to heap base addr when _stksize == -1L || _initial_stack || When DA */
  73. void *_heapbase;
  74.  
  75. /* default sizeof stdio buffers */
  76. size_t __DEFAULT_BUFSIZ__;    /* .comm             */
  77.  
  78. /* are we an app? */
  79. short _app;
  80.  
  81. static long parseargs();
  82. static void setup_handlers    __PROTO((void));
  83. __EXTERN void _main    __PROTO((long, char **, char **));
  84. __EXTERN void _init_signal    __PROTO((void));
  85. __EXTERN void _monstartup __PROTO((void *lowpc, void *highpc));
  86. __EXTERN void __mcleanup __PROTO((void));
  87. __EXTERN void _moncontrol __PROTO((long));
  88. __EXTERN void _setstack __PROTO((char *));
  89.  
  90. /*
  91.  * accessories start here:
  92.  */
  93.  
  94. static char    *acc_argv[] = {"", (char *) 0}; /* no name and no arguments */
  95.  
  96. void _acc_main()
  97. {
  98.     if (_stksize == 0 || _stksize == -1L)
  99.         _stksize = MINKEEP;
  100.  
  101.     if (_stksize < 0)
  102.         _stksize = -_stksize;
  103.     _stksize &= 0xfffffffe;        /* stack on word boundary */
  104.  
  105.     if (_heapbase == 0) {
  106.         _heapbase = (void *)Malloc(_stksize);
  107.     }
  108.     _setstack((char *)_heapbase + _stksize);
  109.     _app = 0;                /* this is an accessory */
  110.     _main(1L, acc_argv, acc_argv);
  111.     /*NOTREACHED*/
  112. }
  113.  
  114. void _crtinit()
  115. {
  116.     register BASEPAGE *bp;
  117.     register long m;
  118.     register long freemem;
  119.  
  120.     _app = 1;    /* its an application */
  121.     if(!__DEFAULT_BUFSIZ__)
  122.         __DEFAULT_BUFSIZ__ = BUFSIZ;
  123.  
  124.     bp = _base;
  125.     m = parseargs(bp);    /* m = # bytes used by environment + args */
  126.  
  127. /* make m the total number of bytes required by program sans stack/heap */
  128.     m += (bp->p_tlen + bp->p_dlen + bp->p_blen);
  129.     m = (m + 3L) & (~3L);
  130. /* freemem the amount of free mem accounting for MINFREE at top */
  131.     if((freemem = (long)bp->p_hitpa - (long)bp->p_tbase - MINFREE - m) <= 0L)
  132.         goto notenough;
  133.     
  134.     if(_initial_stack)
  135.     {
  136.         /* the primary use of _initial_stack will be in dumping */
  137.         /* applications where only a heap for malloc makes sense */
  138.         _heapbase = (void *) ((long)bp->p_tbase + m);
  139.         _stksize = _initial_stack;
  140.     }
  141.     
  142.     switch(_stksize)
  143.     {
  144.       case -1L:    /* keep all but MINFREE, and malloc from own heap */
  145.         _stksize = freemem;
  146.         _heapbase = (void *) ((long)bp->p_tbase + m);
  147.         break;
  148.         
  149.       case 0L:    /* free all but MINKEEP */
  150.         _stksize = MINKEEP;
  151.         break;
  152.  
  153.       case 1L:    /* keep 1/4, free 3/4 */
  154.         _stksize = freemem >> 2;
  155.         break;
  156.  
  157.       case 2L:    /* keep 1/2, free 1/2 */
  158.         _stksize = freemem >> 1;
  159.         break;
  160.  
  161.       case 3L:    /* keep 3/4, free 1/4 */
  162.         _stksize = freemem - (freemem >> 2); 
  163.         break;
  164.         
  165.       default:
  166.         if(_stksize < -1L) { /* keep |_stksize|, use heap for mallocs */
  167.         _stksize = -_stksize;
  168.         _heapbase = (void *)((long)bp->p_tbase + m);
  169.         }
  170.     }
  171.     
  172. /* make m the total number of bytes including stack */
  173.     _stksize = _stksize & (~3L);
  174.     m += _stksize;
  175.  
  176. /* make sure there's enough room for the stack */
  177.     if ((((long)bp->p_tbase) + m) > ((long)bp->p_hitpa - MINFREE))
  178.         goto notenough;
  179.  
  180. /* set up the new stack to bp->p_tbase + m  */
  181.     _setstack(bp->p_tbase + m);
  182.  
  183. /* shrink the TPA */
  184. /* this is right only if bp == bp->p_tbase - sizeof(BASEPAGE) */
  185.     (void)Mshrink(bp, m + sizeof(BASEPAGE));
  186.     
  187. /* establish handlers,  call the main routine */
  188.     setup_handlers();
  189.  
  190. /* start profiling, if we were linked with crt0.o */
  191.     _monstartup((void *)(bp->p_tbase), 
  192.            (void *)((long)bp->p_tbase +  bp->p_tlen));
  193.  
  194.     _main(argc, argv, environ);
  195.     /* not reached normally */
  196.  
  197. notenough:
  198.     Cconws("Fatal error: insufficient memory\r\n");
  199.         Pterm(-1);
  200. }
  201.  
  202.  
  203. /*
  204.  * parseargs(bp): parse the environment and arguments pointed to by the
  205.  * basepage. Return the number of bytes of environment and arguments
  206.  * that have been appended to the bss area (the environ and argv arrays
  207.  * are put here, as is a temporary buffer for the command line, if
  208.  * necessary).
  209.  *
  210.  * The MWC extended argument passing scheme is assumed.
  211.  *
  212.  */
  213.  
  214. static long parseargs(bp)
  215.     BASEPAGE *bp;
  216. {
  217.     long count = 4;        /* compensate for aligning */
  218.     long  i;
  219.     char *from, *cmdln, *to;
  220.     char **envp, **arg;
  221. /* flag to indicate desktop-style arg. passing */
  222.     long desktoparg = 0;
  223.  
  224. /* handle the environment first */
  225.  
  226.     environ = envp = (char **)(( (long)bp->p_bbase + bp->p_blen + 4) & (~3));
  227.     from = bp->p_env;
  228.     while (*from) {
  229.  
  230. /* if we find MWC arguments, tie off environment here */
  231.         if (*from == 'A' && *(from+1) == 'R' && *(from+2) == 'G' &&
  232.             *(from+3) == 'V' && *(from+4) == '=') {
  233.             *envp++ = (char *) 0; count += 4;
  234.             *from++ = 0;
  235. #ifdef STRICTLY_COMPATIBLE_WITH_STANDARD
  236.             if (bp->p_cmdlin[0] != 127)
  237.                 goto old_cmdlin;
  238. #endif
  239.             while (*from++) ; /* skip ARGV= string */
  240.             argv = arg = envp++;
  241.             *arg++ = from; count+= 4;
  242.             while (*from++) ; /* skip argv[0] */
  243.             goto do_argc;
  244.         }
  245.         *envp++ = from;
  246.         count += 4;
  247.         desktoparg = 1;
  248.         while (*from) {
  249.             if (*from == '=') {
  250.                 desktoparg = 0;
  251.             }
  252.             from++;
  253.         }
  254.         from++;        /* skip 0 */
  255.  
  256. /* the desktop (and some shells) use the environment in the wrong
  257.    way, putting in "PATH=\0C:\0" instead of "PATH=C:". so if we
  258.    find an "environment variable" without an '=' in it, we
  259.    see if the last environment variable ended with '=\0', and
  260.    if so we append this one to the last one
  261.  */
  262.         if(desktoparg && envp > &environ[1]) 
  263.         {
  264.         /* launched from desktop -- fix up env */
  265.             char *p, *q;
  266.  
  267.             q = envp[-2];    /* current one is envp[-1] */
  268.             while (*q) q++;
  269.             if (q[-1] == '=') {
  270.             p = *--envp;
  271.             while(*p)
  272.                *q++ = *p++;
  273.                 *q = '\0';
  274.            }
  275.         }
  276.     }
  277.     *envp++ = (char *)0;
  278.     count += 4;
  279.  
  280. #ifdef STRICTLY_COMPATIBLE_WITH_STANDARD
  281. old_cmdlin:
  282. #endif
  283. /* Allocate some room for the command line to be parsed */
  284.     cmdln = bp->p_cmdlin;
  285.     i = *cmdln++;
  286.     from = to = (char *) envp;
  287.     if (i > 0) {
  288.         count += (i&(~3));
  289.         envp = (char **) ( ((long) envp)  + (i&(~3)) );
  290.     }
  291.     envp += 2; count += 8;
  292.  
  293. /* Now parse the command line and put argv after the environment */
  294.  
  295.     argv = arg = envp;
  296.     *arg++ = "";        /* argv[0] not available */
  297.     count += 4;
  298.     while(i > 0 && isspace(*cmdln) )
  299.         cmdln++,--i;
  300.  
  301.     while (i > 0) {
  302.         if (isspace(*cmdln)) {
  303.             --i; cmdln++;
  304.             while (i > 0 && isspace(*cmdln))
  305.                 --i,cmdln++;
  306.             *to++ = 0;
  307.         }
  308.         else {
  309.             if (!(*to++ = *cmdln++)) break;
  310.             --i;
  311.         }
  312.     }
  313.     *to++ = '\0';
  314.     *to = '\0'; /* bug fix example:cmdln == '\3' 'a' ' ' 'b' '\0' */
  315.     /* the loop below expects \0\0 at end to terminate! */
  316.     /* the byte @ cmdln[i+2] != 0 when fast bit is set */
  317. do_argc:
  318.     argc = 1;        /* at this point argv[0] is done */
  319.     while (*from) {
  320.         *arg++ = from;
  321.         argc++;
  322.         count += 4;
  323.         while(*from++) ;
  324.     }
  325.     *arg++ = (char *) 0;
  326.     return count+4;
  327. }
  328.  
  329. static void setup_handlers()
  330. {
  331.     _init_signal();
  332. }
  333.  
  334. /*
  335.  * _exit: does the actual exiting. Note that _moncontrol and __mcleanup are
  336.  * dummies in crt0.s, but do something in gcrt0.s
  337.  */
  338.  
  339. void _exit(status)
  340.     int status;
  341. {
  342.     _moncontrol(0L);
  343.     __mcleanup();
  344.     Pterm(status);
  345. }
  346.